package de.jmda.core.util;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;

import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import de.jmda.core.MarkerAnnotationType;
import de.jmda.core.mproc.Processor;
import de.jmda.core.util.JavaCompilerUtil;

public class JUTJavaCompilerUtil
{
	private List<File> files;
	
	@Before
	public void before()
	{
		files = new ArrayList<>();
	}
	
	@After
	public void after()
	{
		for (File file : files)
		{
			file.delete();
		}
	}

	/**
	 * runs a single processor on a single compilation unit
	 * @throws IOException
	 */
	@Test
	public void runProcessorsOnlySingleCompilationUnitSingleProcessor()
			throws IOException
	{
		Iterable<? extends JavaFileObject> compilationUnits =
				createCompilationUnits(1);
		Iterable<? extends Processor> processors = createProcessors(1);
		JavaCompilerUtil.runProcessorsOnly(compilationUnits, processors);
	}

	/**
	 * runs a single processor on a multiple compilation units
	 * @throws IOException
	 */
	@Test
	public void runProcessorsOnlyMultipleCompilationUnitSingleProcessor()
			throws IOException
	{
		Iterable<? extends JavaFileObject> compilationUnits =
				createCompilationUnits(2);
		Iterable<? extends Processor> processors = createProcessors(1);
		JavaCompilerUtil.runProcessorsOnly(compilationUnits, processors);
	}

	private Iterable<? extends JavaFileObject> createCompilationUnits(int count)
			throws IOException
  {
		List<JavaFileObject> result = new ArrayList<>();
		
		for (int i = 0; i < count; i++)
		{
			result.add(createCompilationUnit(i));
		}
		
	  return result;
  }

	private JavaFileObject createCompilationUnit(int i) throws IOException
  {
		String typename = "__DynaCode__" + i;
		File file = new File(typename + Kind.SOURCE.extension);
		FileUtils.writeStringToFile(
				file,
				"@" + MarkerAnnotationType.class.getName() +  " " +
				"public class " + typename + " {}");
		files.add(file);

		return
				JavaCompilerUtil.createJavaCompiler()
				                .getStandardFileManager(null, null, null)
				                .getJavaFileObjects(file)
				                .iterator()
				                .next();
  }

	private Iterable<? extends Processor> createProcessors(int count)
  {
		List<Processor> result = new ArrayList<>();
		
		for (int i = 0; i < count; i++)
		{
			result.add(createProcessor(i));
		}

		return result;
  }

	private Processor createProcessor(int i)
  {
	  return new PrivateProcessor(i);
  }

	@SupportedAnnotationTypes({"de.jmda.core.MarkerAnnotationType"})
	private class PrivateProcessor extends Processor
	{
		private int i;

		private PrivateProcessor(int i)
		{
			super();
			this.i = i;
		}

		@Override
    protected Set<Class<? extends Annotation>> getSupposedSupportedAnnotationTypes()
    {
	    return asSet(MarkerAnnotationType.class);
    }

		@Override
    protected boolean process()
    {
			System.out.println(getClass().getName() + " running, i = " + i);
	    return false;
    }
	}
}